package seacher;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

// 这个类是用来完成整个搜索过程
public class DocSearch {
    // 此处加上索引对象实例
    private Index index = new Index();

    // 同时完成索引加载工作（加载到内存中）
    public DocSearch() {
        index.load();
    }

    // 这是核心：完成整个搜索的过程的方法
    // 参数（query）就是用户查询词
    // 返回值（输出部分）就是搜索结果的集合
    public List<Result> search(String query) {
        // 1、【分词】针对 query这个词进行分词
        List<Term> terms = ToAnalysis.parse(query).getTerms();
        // 2、【触发】针对分词结果查倒排
        List<Weight> allTermResult = new ArrayList<>();
        for (Term term : terms) {
            String word = term.getName();
            // 查找倒排索引的词，虽然倒排索引中有很多的词，但是这里的词一定都是之前文档中存在的
            List<Weight> invertedList = index.getInverted(word);
            if (invertedList == null) {
                // 没有这个词，就跳过
                continue;
            }
            // addAll是加入一组词，add是一个
            allTermResult.addAll(invertedList);
        }
        // 3、【排序】针对触发结果按照权重来降序排序
        allTermResult.sort(new Comparator<Weight>() {
            @Override
            public int compare(Weight o1, Weight o2) {
                // 升序：o1-o2
                // 降序：o2-o1
                return o2.getWeight() - o1.getWeight();
            }
        });
        // 4、【包装结果】针对排序结果，去查正排，构造出要返回的数据
        List<Result> results = new ArrayList<>();
        for (Weight weight : allTermResult) {
            DocInfo docInfo = index.getDocInfo(weight.getDocId());
            Result result = new Result();
            result.setTitle(docInfo.getTitle());
            result.setUrl(docInfo.getUrl());
            // 描述是需要依赖正文，和分词结果
            result.setDesc(GenDesc(docInfo.getContent(), terms));
            results.add(result);
        }
        return results;
    }

    private String GenDesc(String content, List<Term> terms) {
        // 1、先遍历分词结果, 看看哪个结果是在 content 中存在.
        int firstPose = -1;
        for (Term term : terms) {
            // 2、别忘了, 分词库直接针对词进行转小写了.
            String word = term.getName();
            // 正因为如此, 就必须把正文也先转成小写, 然后再查询
            // 3、还有个问题，此处需要“全字匹配”，让word成为独立词，才可以查找出来，而不是作为词的一部分
            // 此处的全字匹配做的不严谨，更严谨的做法是使用正确的正则表达式
            firstPose = content.toLowerCase().indexOf(" " + word + " ");//直接的方法word两边加上空格
            if (firstPose >= 0) {
                // 找了分词结果的位置
                break;
            }
            if (firstPose == -1) {
                // 所有分词结果都不在正文中存在，属于比较极端情况，可以返回空的描述
                // 或者也可以直接取正文的前 160 个字符作为描述
                if (content.length() > 160) {
                    return content.substring(0, 160) + "...";
                }
            }
            // 4、从 firstPos 作为基准位置, 往前找 60 个字符, 作为描述的起始位置.
            String desc = "";
            int descBeg = firstPose < 60 ? 0 : firstPose - 60;
            if (descBeg + 160 > content.length()) {
                desc = content.substring(descBeg);
            } else {
                desc = content.substring(descBeg, descBeg + 160) + "...";
            }
            return desc;
        }
        return null;
    }

    public static void main(String[] args) {
        DocSearch docSearch = new DocSearch();
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("-->");
            String query = scanner.next();
            List<Result> results = docSearch.search(query);
            for (Result result:results) {
                System.out.println("=================================");
                System.out.println(result);
            }
        }

    }
}
